
#include <BAudioOutput>
#include "member_BAudioOutput.h"

using namespace BWE;
#define member					(*(member_BAudioOutput*)_ptr)
#define member_allocate()		_ptr = new member_BAudioOutput
#define member_release()		delete (member_BAudioOutput*)_ptr
#define audio_member(audio)		((member_BAudioOutput*)audio->_ptr)

BList<BAudioOutput*>	AudioOutputList;
#ifdef _WINDOWS_SYSTEM_
void CALLBACK waveOutProc(HWAVEOUT hWaveOut, UINT uMsg, DWORD_PTR dwInstance, DWORD_PTR dwParam1, DWORD_PTR dwParam2)
{
	for(BList<BAudioOutput*>::iterator it = AudioOutputList.begin(); it != AudioOutputList.end(); it++)
	{
		BAudioOutput* audio = it.value();
		member_BAudioOutput* mem = audio_member(audio);
		if(mem->hWaveOut == hWaveOut)
		{
			mem->callback(audio);
		}
		if(WOM_DONE == uMsg)
		{

		}
	}
}
BAudioOutput::BAudioOutput()
{
	member_allocate();
	AudioOutputList.append(this);
	int num = waveOutGetNumDevs();  
	for(int i = 0; i < num; i++)
	{  
		WAVEOUTCAPS woc;  
		waveOutGetDevCaps(i, &woc, sizeof(WAVEOUTCAPS));  
		member.deviceNames.append(woc.szPname);
	}
}

BAudioOutput::~BAudioOutput()
{
	AudioOutputList.remove(this);
	member_release();
}

bool BAudioOutput::open()
{
	MMRESULT result = waveOutOpen(&member.hWaveOut, WAVE_MAPPER, &member.wavform, (DWORD_PTR)waveOutProc, 0, CALLBACK_FUNCTION);
	switch(result)
	{
	case MMSYSERR_NOERROR:
		member.log("audio open successful................");
		return true;
	case MMSYSERR_ALLOCATED:
		member.log("Specified resource is already allocated.");
		break;
	case MMSYSERR_BADDEVICEID:
		member.log("Specified device identifier is out of range.");
		break;
	case MMSYSERR_NODRIVER:
		member.log("No device driver is present.");
		break;
	case MMSYSERR_NOMEM:
		member.log("Unabled to allocate or lock memory.");
		break;
	case WAVERR_BADFORMAT:
		member.log("Attempted to open with an unsupported waveform-audio format.");
		break;
	case WAVERR_SYNC:
		member.log("The device is synchronous but waveOutOpen was called without using the WAVE_ALLOWSYNC flag.");
		break;
	}
	WAVEOUTCAPS woc;
	waveOutGetDevCaps((UINT_PTR)member.hWaveOut, &woc, sizeof(WAVEOUTCAPS));  
	return false;
}
bool BAudioOutput::close()
{
	waveOutReset(member.hWaveOut);
	waveOutUnprepareHeader(member.hWaveOut, &member.wavhdr, sizeof(WAVEHDR));
	waveOutClose(member.hWaveOut);
	return true;
}

bool BAudioOutput::play()
{
	waveOutPrepareHeader(member.hWaveOut, &member.wavhdr, sizeof(WAVEHDR));
	waveOutWrite(member.hWaveOut, &member.wavhdr, sizeof(WAVEHDR));
	return true;
}
bool BAudioOutput::pause()
{
	 return true;
}
bool BAudioOutput::stop()
{
	 return true;
}

int BAudioOutput::deviceNumber() const
{
	return member.deviceNames.size();
}
BString BAudioOutput::deviceName(int index) const
{
	return member.deviceNames(index);
}

void BAudioOutput::setBuffer(const BByteArray& data)
{
	member.buffer = data;

	member.wavhdr.lpData = (LPSTR)data.data();
	member.wavhdr.dwBufferLength = data.size();
	member.wavhdr.dwFlags = 0;
	member.wavhdr.dwLoops = 0;
}
const BByteArray& BAudioOutput::buffer() const
{
	return member.buffer;
}
void BAudioOutput::clean()
{
	member.buffer.clear();
	member.wavhdr.lpData = (LPSTR)member.buffer.data();
	member.wavhdr.dwBufferLength = member.buffer.size();
	member.wavhdr.dwFlags = 0;
	member.wavhdr.dwLoops = 0;
}

bool BAudioOutput::audioEvent(const BAudioEvent& audioEvent)
{
	return true;
}
#endif
